老大最近说公司要开始做新的项目,给一些相关 IM 通信方面的资料。目前仅仅对 Socket
和 WebSocket
一些基本知识进行整理。
下面整理出 HTTP/IP
相关知识思维导图
Socket
简介
Socket
起源
Socket
是一种文件描述,起源于 Unix
。所以 Socket
采用 Unix
一切皆文件核心,符合 打开 open –>读写 write/read –> 关闭 close
模式。
Socket
又被称为:套接字。在网络中两个进行进行通信 Socket
是其基石,同时也是支持 TCP/IP
协议的网络通信的基本单元。Socket
本质来说不是协议而是对于 TCP/IP
的抽象,包含网络通信的物种基本信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。
TCP/IP
基础知识
小编在此向大家简单的介绍一些关于 TCP/IP
基本知识。从字面上来说 TCP/IP
是两种协议,但是我们通常依次来代指整个 TCP/IP
协议族代称。我们在 ISO
模型分为七层,但是在 TCP/IP
协议分为四层:应用层、传输层、网络层和数据链路层。
下面列举每层一些相关协议:
- 应用层:
HTTP
,FTP
,SMTP
,DNS
,Telnet
等 - 传输层:
UDP
,TCP
- 网络层:
IGMP
,ICMP
,IP
- 数据链路层:
MTU
,SLIP
,CSLIP
,PPP
等
上面的四层网络从高到低,每一层抽象层都是是建立在低一层的服务上面并且为高层提供服务。
下面给出在 TCP/IP
和 ISO
分层结构和关系图:
【图片来源于网络】
【图片来源于网络】
Socket
使用
小编在上面介绍过 Socket
基本概念和 TCP/IP
一些基本知识,下面将介绍 Socket
一些实现流程、使用和实现的原理。
使用流程
Socket
在TCP/IP
分层应用
上文小编提到 Socket
是对 TCP/IP
的一些封装,下面给出图来详细介绍:
Socket
通信流程
由上图我们看出 Socket
信息交互流程:
(1)服务器(server)根据地质类型(IPV4/IPV6)和
Socket
类型,协议创建Socket
;
(2)server 绑定Socket
和 宿主源的端口号以及 IP 地址;
(3)server 监听上述绑定的端口,随时接受Socket
请求。但此时并没有开启Socket
;
(4)客户端(client) 创建Socket
;
(5)client 指定源的端口和 IP 地址,并申请链接;
(6)server 接收到请求链接请求被动打开,开始jieshou客户端请求。这时accept
处于阻塞状态,知道 client 信息返回后才可以接受下一个Socket
;
(7)client 向 server 向Socket
发送细信息;
(8)server 接受Socket
读取其中的信息;
(9)client 关闭Socket
;
(10)server 关闭Socket
。
在上述(5)~(6)过程瞒住我们在 TCP
中见到的经典的三次握手🤝如下图:
第一次握手:客户端尝试连接服务器,向服务器发送
syn
包(同步序列编号Synchronize Sequence Numbers
),syn=j
,客户端进入SYN_SEND
状态等待服务器确认第二次握手:服务器接收客户端
syn
包并确认(ack=j+1
),同时向客户端发送一个SYN
包(syn=k
),即SYN+ACK
包,此时服务器进入SYN_RECV
状态第三次握手:客户端收到服务器的
SYN+ACK
包,向服务器发送确认包ACK
(ack=k+1
),此包发送完毕,客户端和服务器进入ESTABLISHED
状态,完成三次握手
Socket
API
小编简单了解一下socket
提供了哪些API
供应用程序使用,还是以TCP
协议为例,看看Unix
下的socket API
,小编这里就简单解释一下方法作用和参数。
1 | int socket(int domain, int type, int protocol); |
根据指定的地址族、数据类型和协议来分配一个socket的描述字及其所用的资源。
domain
: 协议族。常用的有AF_INET
、AF_INET6
、AF_LOCAL
、AF_ROUTE
其中AF_INET
代表使用ipv4
地址;
type
:socket
类型。常用的socket
类型有,SOCK_STREAM
、SOCK_DGRAM
、SOCK_RAW
、SOCK_PACKET
、SOCK_SEQPACKET
等
protocol
:协议。常用的协议有,IPPROTO_TCP
、IPPTOTO_UDP
、IPPROTO_SCTP
、IPPROTO_TIPC
等
1 | int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); |
把一个地址族中的特定地址赋给socket。
sockfd
:socket
描述字,也就是socket
引用
addr
:要绑定给sockfd
的协议地址
addrlen
:地址的长度
通常服务器在启动的时候都会绑定一个众所周知的地址(如ip
地址+端口号),用于提供服务,客户就可以通过它来接连服务器;而客户端就不用指定,有系统自动分配一个端口号和自身的ip
地址组合。这就是为什么通常服务器端在listen
之前会调用bind()
,而客户端就不会调用,而是在connect()
时由系统随机生成一个。
1 | int listen(int sockfd, int backlog); |
监听socket
。
sockfd
:要监听的socket
描述字
backlog
:相应socket可以排队的最大连接个数
1 | int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); |
连接某个socket
。
sockfd
:客户端的socket
描述字
addr
:服务器的socket
地址
addrlen
:socket
地址的长度
1 | int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); |
TCP
服务器监听到客户端请求之后,调用accept()
函数取接收请求。
sockfd
:服务器的socket
描述字
addr
:客户端的socket
地址
addrlen
:socket
地址的长度
1 | ssize_t read(int fd, void *buf, size_t count); |
读取socket
内容。
fd
:socket
描述字
buf
:缓冲区
count
:缓冲区长度
1 | ssize_t write(int fd, const void *buf, size_t count); |
向socket
写入内容,其实就是发送内容。
fd
:socket
描述字
buf
:缓冲区
count
:缓冲区长度
1 | int close(int fd); |
socket
标记为以关闭 ,使相应socket
描述字的引用计数-1
,当引用计数为0
的时候,触发TCP
客户端向服务器发送终止连接请求。
参考地址:
socket实现原理和机制
Java TCP/IP Socket 编程
Socket.md
Linux Socket编程(不限Linux)